package com.ziyue.socket.util;




import com.ziyue.socket.util.bean.ConstructorParams;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wancheng on 2019/4/2.
 *         反射工具类
 */
public class ReflectUtil {

    /**
     * 反射获取class实例
     *
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T getInstance(Class<? extends T> tClass) {
        try {
            return tClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构造方法获取对象实例,可以传入构造参数
     * @param tClass
     * @param constructorParams
     * @param <T>
     * @return
     */
    public static <T> T getInstanceWithConstructor(Class<? extends T> tClass, ConstructorParams... constructorParams) {
        List<ConstructorParams> params = Arrays.asList(constructorParams);
        List<Class<?>> paramClass = params.stream().map(ConstructorParams::getParamClazz).collect(Collectors.toList());
        Class<?>[] keyArray = new Class<?>[paramClass.size()];
        List<Object> paramValue = params.stream().map(ConstructorParams::getParamValue).collect(Collectors.toList());
        Object[] valueArray = new Object[paramValue.size()];
        Constructor<T> cons = null;
        paramClass.toArray(keyArray);
        try {
            cons = (Constructor<T>) tClass.getConstructor(keyArray);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            return cons != null ? cons.newInstance(paramValue.toArray(valueArray)) : null;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取参数
     *
     * @param obj
     * @return
     */
    public static List<String> getClassAttribute(Class<?> obj) {
        List<String> attributes = new ArrayList<>();
        Field[] fields = obj.getDeclaredFields();
        Arrays.stream(fields).forEach(
                field -> attributes.add(field.getName())
        );
        return attributes;
    }

    /**
     * 对象反射传入参数
     *
     * @param obj
     * @param arrtibute
     * @param value
     * @param <T>
     * @return
     */
    public static <T> T setAttribute(T obj, String arrtibute, Object value) {
        System.out.println(value.getClass());
        Field[] fields = obj.getClass().getDeclaredFields();
        Arrays.stream(fields).filter(
                field -> field.getName().equals(arrtibute)
        ).forEach(
                field -> {
                    field.setAccessible(true);

                    try {
                        Class<?> typeclass = field.getType();
                        if (typeclass.equals(Integer.class)) {
                            field.set(obj, Integer.valueOf(String.valueOf(value)));
                        } else if (typeclass.equals(String.class)) {
                            field.set(obj, String.valueOf(value));
                        } else if (typeclass.equals(Double.class)) {
                            field.set(obj, Double.valueOf(String.valueOf(value)));
                        } else if (typeclass.equals(Float.class)) {
                            field.set(obj, Float.valueOf(String.valueOf(value)));
                        } else if (typeclass.equals(Byte.class)) {
                            field.set(obj, Byte.valueOf(String.valueOf(value)));
                        } else if (typeclass.equals(Date.class)) {

                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
        );
        return obj;
    }

    /**
     * 反射转换
     *
     * @param map
     * @param beanClass
     * @return
     * @throws Exception
     */
    public static <T> T mapToObjectReflect(Map<String, Object> map, Class<T> beanClass) throws Exception {
        if (map == null) {
            return null;
        }
        T obj = beanClass.newInstance();

        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }

            field.setAccessible(true);
            field.set(obj, map.get(field.getName()));
        }
        return obj;
    }

    /**
     * 反射转换
     *
     * @param obj
     * @return
     * @throws Exception
     */
    public static Map<String, Object> objectToMapReflect(Object obj) throws Exception {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();

        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }

    /**
     * 内省转换
     *
     * @param map
     * @param beanClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T mapToObjectIntrospect(Map<String, Object> map, Class<T> beanClass) throws Exception {
        if (map == null) {
            return null;
        }
        T obj = beanClass.newInstance();
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            if (setter != null) {
                setter.invoke(obj, map.get(property.getName()));
            }
        }
        return obj;
    }

    /**
     * 内省转换
     *
     * @param obj
     * @return
     * @throws Exception
     */
    public static Map<String, Object> objectToMapIntrospect(Object obj) throws Exception {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            String key = property.getName();
            if (key.compareToIgnoreCase("class") == 0) {
                continue;
            }
            Method getter = property.getReadMethod();
            Object value = getter != null ? getter.invoke(obj) : null;
            map.put(key, value);
        }
        return map;
    }
}
